import cluster from 'cluster';
import { IOptions } from '../index';
import { cpus } from 'os';
import { startAndWritePid } from './pidManager';

export default class {
  options: IOptions;
  interval: any = -1;
  exitInterval: any = -1;
  /** 重试次数 */
  retried = 0;
  /** 最多可重试次数 */
  MAX_RETRY: number;
  /** 是否通知父进程 */
  IS_NOTIFY = false;

  /**
   * @param options 启动配置
   * @param MAX_RETRY 最多可重试次数
   */
  constructor(options: IOptions, maxRetry = 5) {
    this.options = options;
    this.MAX_RETRY = maxRetry;
  }

  /**
   * 启动
   * @param scriptFile 脚本文件地址
   */
  async setup(scriptFile: string): Promise<void> {
    if (cluster.isMaster) {
      const count = this.getMaxWorkers();
      for (let i = 0; i < count; i++) {
        cluster.fork();
      }

      cluster.on('exit', () => {
        this.canExit();
        clearTimeout(this.interval);
        if (this.retried <= this.MAX_RETRY) {
          this.retried++;
          cluster.fork();
        }
      });
      cluster.on('message', (worker, msg) => {
        if (!this.IS_NOTIFY) {
          process.send && process.send(msg);
          this.IS_NOTIFY = true;
        }
      });
      await startAndWritePid({ id: this.options.id || '', pid: process.pid });
    } else {
      const fn = await import(scriptFile);
      fn.default(this.options);
      this.reset();
    }
  }

  /**
   * 最多启用两个worker
   */
  getMaxWorkers(): number {
    return cpus().length > 1 ? 2 : 1;
  }

  /**
   * 5秒内没有触发exit，则认为成功启动worker
   */
  reset(): void {
    clearTimeout(this.exitInterval);
    this.interval = setTimeout(() => {
      this.retried = 0;
    }, 5000);
  }

  canExit(): void {
    this.exitInterval = setTimeout(() => {
      if (Object.keys(cluster.workers).length === 0) {
        process.exit();
      }
    }, 5000);
  }
}
